#!/usr/bin/python
# -*- coding: utf-8 -*-
# Description: 生成数字签名数据
# Create: 2008-7-6
# Author: MK2[fengmk2@gmail.com]
import os
import time
from datetime import datetime
from xml.dom.minidom import Document
import codecs 
import asn1
from fileauth.public.utility import common as util

class ASN1Container(object):
    """"""
    def __init__(self, **kwargs):
        for key, value in kwargs.items():
                setattr(self, key, value)
            
    def __repr__(self):
        return str(self.__dict__)
    
    @property
    def name(self):
        return str(self.__class__).split('.')[1]
    
    def check_type(self, instance, want_cls):
        if not isinstance(instance, want_cls):
            raise ValueError('We want "%s", but now is "%s"' % (want_cls, instance.__class__))

class AttributeTypeAndValue(ASN1Container):
    """AttributeTypeAndValue ::= SEQUENCE {
     type     AttributeType,
     value    AttributeValue }
   AttributeType ::= OBJECT IDENTIFIER
   AttributeValue ::= ANY DEFINED BY AttributeType
    """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Sequence)
        self.Type = str(asn1_obj[0])
        try:
            self.Value = asn1_obj[1].val
        except:
            self.Value = asn1_obj[1]

class RelativeDistinguishedName(list):
    """RelativeDistinguishedName ::= SET OF AttributeTypeAndValue
    """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Set)
        self.extend([AttributeTypeAndValue(i) for i in asn1_obj])
         
class RDNSequence(list):
    """RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
    """
    def __init__(self, asn1_obj):
#        assert isinstance(asn1_obj, asn1.Sequence)
        self.extend([RelativeDistinguishedName(i) for i in asn1_obj])
    
    def __repr__(self):
        return os.linesep.join(['%s = %s' % (i[0].Type, i[0].Value) \
                                    for i in self])
        
class IssuerAndSerialNumber(ASN1Container):
    """IssuerAndSerialNumber ::= SEQUENCE {  -- Uniquely identifies certificate
           issuer        Name,
           serialNumber  CertificateSerialNumber}
    """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Sequence)
        self.Name = str(RDNSequence(asn1_obj[0]))
        self.Serialnumber = asn1_obj[1].val

class SpcString(ASN1Container):
    """SpcString ::= CHOICE {
    unicode                 [0] IMPLICIT BMPSTRING,
    ascii                   [1] IMPLICIT IA5STRING}
    """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Contextual)
        if asn1_obj.tag == 0:
            self.unicode = ''#unicode(asn1_obj.val)
        elif asn1_obj.tag == 1:
            self.ascii = asn1_obj.val

class SpcSerializedObject(ASN1Container):
    """SpcSerializedObject ::= SEQUENCE {
    classId             SpcUuid,
    serializedData      OCTETSTRING}

SpcUuid ::= OCTETSTRING

The serializedData field contains a binary structure. 
When present in an Authenticode signature generated in Windows Vista, 
serializedData contains a binary structure that contains page hashes. 

binary_struc ::= SET {
    SEQUENCE {
        OID,
        SET { OCT: Hash }
    }
}
    """
    def __init__(self, asn1_obj):
#        assert isinstance(asn1_obj, asn1.Sequence)
        self.ClassId = asn1_obj[0].str
        if asn1_obj[1].encapsulate:
            binary_struc = asn1_obj[1].val[0]
            self.SerializedData = ASN1Container(OID=str(binary_struc[0]), 
                                                Hash=binary_struc[1][0].str)
    
class SpcLink(ASN1Container):
    """SpcLink ::= CHOICE {
        url                     [0] IMPLICIT IA5STRING,
        moniker                 [1] IMPLICIT SpcSerializedObject,
        file                    [2] EXPLICIT SpcString}
    """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Contextual)
        if asn1_obj.tag == 0:
            self.URL = asn1_obj.val
        elif asn1_obj.tag == 1:
            self.Moniker = SpcSerializedObject(asn1_obj)
        else:
            self.File = SpcString(asn1_obj[0])
    
class SpcSpOpusInfo(ASN1Container):
    """
    SpcSpOpusInfo ::= SEQUENCE {
        programName             [0] EXPLICIT SpcString OPTIONAL,
        moreInfo                [1] EXPLICIT SpcLink OPTIONAL,
    }
    """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Sequence)
        if asn1_obj:
            if asn1_obj[0].tag == 0:
                self.ProgramName = SpcString(asn1_obj[0][0])
            if len(asn1_obj) > 1:
                if asn1_obj[1].tag == 1:
                    self.MoreInfo = SpcLink(asn1_obj[1][0])

class Attribute(ASN1Container):
    """http://www.alvestrand.no/objectid/1.2.840.113549.1.9.html
    http://tools.ietf.org/html/rfc3369
    * 1.2.840.113549.1.9.1 - e-mailAddress
    * 1.2.840.113549.1.9.2 - PKCS-9 unstructuredName
    * 1.2.840.113549.1.9.3 - contentType
    * 1.2.840.113549.1.9.4 - messageDigest
    * 1.2.840.113549.1.9.5 - Signing Time
    * 1.2.840.113549.1.9.7 - Challenge Password
    * 1.2.840.113549.1.9.8 - PKCS-9 unstructuredAddress
    * 1.2.840.113549.1.9.13 - Signing Description
    * 1.2.840.113549.1.9.15 - S/Mime capabilities
    * 1.2.840.113549.1.9.16 - S/MIME Object Identifier Registry
    * 1.2.840.113549.1.9.20 - PKCS-9 Attribute : friendlyName
    * 1.2.840.113549.1.9.22 - certTypes 
    
    ContentType ::= OBJECT IDENTIFIER
    MessageDigest ::= OCTET STRING
    SigningTime ::= Time
      Time ::= CHOICE {
        utcTime          UTCTime,
        generalizedTime  GeneralizedTime }
    Countersignature ::= SignerInfo

    """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Sequence)
        self.OID = str(asn1_obj[0])
        if self.OID == 'SPC_SP_OPUS_INFO':
            assert isinstance(asn1_obj[1][0], asn1.Sequence)
            self.Value = SpcSpOpusInfo(asn1_obj[1][0])
        elif self.OID == 'ContentType':
            assert isinstance(asn1_obj[1][0], asn1.OID)
            self.Value = str(asn1_obj[1][0])
        elif self.OID == 'MessageDigest':
            assert isinstance(asn1_obj[1][0], asn1.OctetString)
            self.Value = asn1_obj[1][0].str
        elif self.OID == 'SigningTime':
            assert isinstance(asn1_obj[1][0], asn1.UTCTime)
            self.Value = asn1_obj[1][0].datetime
        elif self.OID == 'SPC_STATEMENT_TYPE':
            assert isinstance(asn1_obj[1][0], asn1.Sequence)
            self.Value = str(asn1_obj[1][0][0])
        elif self.OID == 'Countersignature':
            assert isinstance(asn1_obj[1][0], asn1.Sequence)
            self.Value = SignerInfo(asn1_obj[1][0])
        else:
            print 'Unknow Attribute', asn1_obj
            pass
        
class SignerInfo(ASN1Container):
    """SignerInfo ::= SEQUENCE {
          version Version,
          issuerAndSerialNumber IssuerAndSerialNumber,
          digestAlgorithm DigestAlgorithmIdentifier,
          authenticatedAttributes
            [0] IMPLICIT Attributes OPTIONAL,
          digestEncryptionAlgorithm
            DigestEncryptionAlgorithmIdentifier,
          encryptedDigest EncryptedDigest,
          unauthenticatedAttributes
            [1] IMPLICIT Attributes OPTIONAL }
        IssuerAndSerialNumber ::= SEQUENCE {
          issuer Name,
          serialNumber CertificateSerialNumber }
        EncryptedDigest ::= OCTET STRING
    """
    def __init__(self, info_asn1):
        assert isinstance(info_asn1, asn1.Sequence)
        self.Version = info_asn1[0].val
        self.IssuerAndSerialnumber = IssuerAndSerialNumber(info_asn1[1])
        self.DigestAlgorithm = AlgorithmIdentifier(info_asn1[2])
        if info_asn1[3].tag == 0:
            self.AuthenticatedAttributes = []
            for i in info_asn1[3]:
                self.AuthenticatedAttributes.append(Attribute(i))
        self.DigestEncryptionAlgorithm = AlgorithmIdentifier(info_asn1[4])
        self.EncryptedDigest = info_asn1[5].str
        if len(info_asn1) > 6:
            if info_asn1[6].tag == 1:
                self.UnAuthenticatedAttributes = []
                for i in info_asn1[6]:
                    self.UnAuthenticatedAttributes.append(Attribute(i))

class SignerInfos(list, ASN1Container):
    """SignerInfos ::= SET OF SignerInfo
    """
    def __init__(self, asn1_obj):
        self.check_type(asn1_obj, asn1.Set)
        self.extend([SignerInfo(i) for i in asn1_obj])
        
class SpcPeImageFlags(ASN1Container):
    """SpcPeImageFlags ::= BIT STRING {
    includeResources            (0),
    includeDebugInfo            (1),
    includeImportAddressTable   (2)
}
    """
    
class SpcPeImageData(ASN1Container):
    """SpcPeImageData ::= SEQUENCE {
           flags                   SpcPeImageFlags DEFAULT { includeResources },
           file                    SpcLink}
    """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Sequence)
        self.Flags = asn1_obj[0].str
        self.File = SpcLink(asn1_obj[1][0])

class SpcAttributeTypeAndOptionalValue(ASN1Container):
    """SpcAttributeTypeAndOptionalValue ::= SEQUENCE {
        type                    ObjectID,
        value                   [0] EXPLICIT ANY OPTIONAL}
    """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Sequence)
        self.Type = str(asn1_obj[0])
        assert self.Type == 'SPC_PE_IMAGE_DATA'
        self.Value = SpcPeImageData(asn1_obj[1])

class AlgorithmIdentifier(ASN1Container):
    """AlgorithmIdentifier ::= SEQUENCE {
   algorithm   ALGORITHM-IDENTIFIER.&id({InfoObjectSet}),
   parameters  ALGORITHM-IDENTIFIER.&Type({InfoObjectSet}
                                                  {@algorithm}) OPTIONAL
}
    """
    def __init__(self, asn1_obj):
        self.check_type(asn1_obj, asn1.Sequence)
        self.Algorithm = str(asn1_obj[0])
        if len(asn1_obj) > 1:
            self.Parameters = str(asn1_obj[1])

class BasicConstraints(ASN1Container):
    """BasicConstraints ::= SEQUENCE {
        CA                      BOOLEAN DEFAULT FALSE,
        PathLenConstraint       INTEGER (0..MAX) OPTIONAL }
    """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Sequence)
        self.CA = 'FALSE'
        if asn1_obj:
            self.CA = asn1_obj[0]
            if len(asn1_obj) > 1:
                self.PathLenConstraint = asn1_obj[1].val

class EDIPartyName(ASN1Container):
    """EDIPartyName ::= SEQUENCE {
     nameAssigner            [0]     DirectoryString OPTIONAL,
     partyName               [1]     DirectoryString }
     
    DirectoryString ::= CHOICE {
     teletexString           TeletexString (SIZE (1..MAX)),
     printableString         PrintableString (SIZE (1..MAX)),
     universalString         UniversalString (SIZE (1..MAX)),
     utf8String              UTF8String (SIZE (1..MAX)),
     bmpString               BMPString (SIZE (1..MAX)) }
    """
    def __init__(self, asn1_obj):
#        assert isinstance(asn1_obj, asn1.Sequence)
        self.NameAssigner = asn1_obj[0].val
        self.PartyName = asn1_obj[1].val

class OtherName(ASN1Container):
    """OtherName ::= SEQUENCE {
        type-id    OBJECT IDENTIFIER,
        value      [0] EXPLICIT ANY DEFINED BY type-id }
    """
    def __init__(self, asn1_obj):
        self.TypeId = asn1_obj[0]
        if asn1_obj[1].tag == 0:
            if asn1_obj[1].constructed:
                self.Value = u','.join([unicode(i) for i in asn1_obj[1].val])
            try:
                if asn1_obj[1].constructed:
                    self.Value = u','.join([unicode(i) for i in asn1_obj[1].val])
            except Exception, e:
                print e
                print asn1_obj[1]
                self.Value = unicode(asn1_obj[1].val)
         
class GeneralName(ASN1Container):
    """GeneralName ::= CHOICE {
     otherName                       [0]     OtherName,
     rfc822Name                      [1]     IA5String,
     dNSName                         [2]     IA5String,
     x400Address                     [3]     ORAddress,
     directoryName                   [4]     Name,
     ediPartyName                    [5]     EDIPartyName,
     uniformResourceIdentifier       [6]     IA5String,
     iPAddress                       [7]     OCTET STRING,
     registeredID                    [8]     OBJECT IDENTIFIER }
    """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Contextual)
        self.Tag = asn1_obj.tag
        if self.Tag == 0:
            self.OtherName = OtherName(asn1_obj.val)
        elif self.Tag == 1:
            self.RFC822Name = asn1_obj.val
        elif self.Tag == 2:
            self.DNSName = asn1_obj.val
        elif self.Tag == 3:
            self.X400Address = ORAddress(asn1_obj[0])
        elif self.Tag == 4:
            self.DirectoryName = str(RDNSequence(asn1_obj.val[0]))
        elif self.Tag == 5:
            self.EdiPartyName = EDIPartyName(asn1_obj.val)
        elif self.Tag == 6:
            self.UniformResourceIdentifier = asn1_obj.val
        elif self.Tag == 7:
            self.IPAddress = asn1_obj.val
        else:
            self.RegisteredID = str(asn1_obj[0])

class GeneralNames(list):
    """GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
    """
    def __init__(self, asn1_obj):
#        assert isinstance(asn1_obj, asn1.Sequence)
        self.extend([GeneralName(i) for i in asn1_obj])
        
class AccessDescription(ASN1Container):
    """AccessDescription  ::=  SEQUENCE {
         accessMethod          OBJECT IDENTIFIER,
         accessLocation        GeneralName  }
    """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Sequence)
        self.AccessMethod = str(asn1_obj[0])
        self.AccessLocation = GeneralName(asn1_obj[1])
             
class AuthorityInfoAccess(list):
    """AuthorityInfoAccess  ::=  SEQUENCE SIZE (1..MAX) OF
                               AccessDescription
    """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Sequence)
        for i in asn1_obj:
            self.append(AccessDescription(i))
        
class DistributionPointName(ASN1Container):
    """DistributionPointName ::= CHOICE {
        fullName                [0]     GeneralName,
        nameRelativeToCRLIssuer [1]     RelativeDistinguishedName }
    """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Contextual)
        if asn1_obj.tag == 0:
            self.FullName = GeneralName(asn1_obj[0])
        else:
            self.NameRelativeToCRLIssuer = RelativeDistinguishedName(asn1_obj[0])

class DistributionPoint(ASN1Container):
    """DistributionPoint ::= SEQUENCE {
        distributionPoint       [0]     DistributionPointName OPTIONAL,
        reasons                 [1]     ReasonFlags OPTIONAL,
        cRLIssuer               [2]     GeneralNames OPTIONAL }

   ReasonFlags ::= BIT STRING {
        unused                  (0),
        keyCompromise           (1),
        cACompromise            (2),
        affiliationChanged      (3),
        superseded              (4),
        cessationOfOperation    (5),
        certificateHold         (6),
        privilegeWithdrawn      (7),
        aACompromise            (8) }
    """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Sequence)
        for i in asn1_obj:
            if i.tag == 0:
                self.Point = DistributionPointName(i[0])
            elif i.tag == 1:
                self.Reasons = ReasonFlags(i.val)
            else:
                self.CRLIssuer = GeneralNames(i.val)
            
class CRLDistributionPoints(list):
    """CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
    """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Sequence)
        self.extend([DistributionPoint(i) for i in asn1_obj])

class ExtKeyUsage(list):
    """ExtKeyUsage ::= SEQUENCE SIZE (1..MAX) OF KeyPurposeId
    KeyPurposeId ::= OBJECT IDENTIFIER
    """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Sequence)
        self.extend([str(i) for i in asn1_obj])

class KeyUsage(list):
    """KeyUsage ::= BIT STRING {
           digitalSignature        (0),
           nonRepudiation          (1),
           keyEncipherment         (2),
           dataEncipherment        (3),
           keyAgreement            (4),
           keyCertSign             (5),
           cRLSign                 (6),
           encipherOnly            (7),
           decipherOnly            (8) }
"""
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.BitString)
        b = asn1_obj.val[0]
        if len(asn1_obj.val) == 2:
            b = b << 8 | asn1_obj.val[1]
        if b & 0x01:
            self.append('Digital Signature')
        if b & 0x02:
            self.append('Non Repudiation')
        if b & 0x04:
            self.append('Key Encipherment')
        if b & 0x08:
            self.append('Data Encipherment')
        if b & 0x10:
            self.append('Key Agreement')
        if b & 0x20:
            self.append('Key CertSign')
        if b & 0x40:
            self.append('CRL Sign')
        if b & 0x80:
            self.append('Encipher Only')
        if b & 0x0100:
            self.append('Decipher Only')
        
class Extension(ASN1Container):
    """ Extension  ::=  SEQUENCE  {
            extnID      OBJECT IDENTIFIER,
            critical    BOOLEAN DEFAULT FALSE,
            extnValue   OCTET STRING  }
    """
    def __init__(self, ext):
        assert isinstance(ext, asn1.Sequence)
        self.ExtnID = str(ext[0])
        if len(ext) == 2:
            self.Critical = 'FALSE'
            next = 1
        else:
            self.Critical = ext[1]
            next = 2
        ext_val_asn1 = ext[next]
        if self.ExtnID == 'KEY_USAGE':
            self.ExtnValue = ', '.join([s for s in KeyUsage(ext_val_asn1.val)])
#            self.ExtnValue = KeyUsage(ext_val_asn1.val)
        elif self.ExtnID == 'AUTHORITY_INFO_ACCESS':
            self.ExtnValue = AuthorityInfoAccess(ext_val_asn1.val)
        elif self.ExtnID == 'BASIC_CONSTRAINTS2':
            self.ExtnValue = BasicConstraints(ext_val_asn1.val)
        elif self.ExtnID == 'CRL_DIST_POINTS':
            self.ExtnValue = CRLDistributionPoints(ext_val_asn1.val)
        elif self.ExtnID == 'ENHANCED_KEY_USAGE':
            self.ExtnValue = ','.join([i for i in ExtKeyUsage(ext_val_asn1.val)])
        elif self.ExtnID == 'SUBJECT_ALT_NAME2':
            self.ExtnValue = GeneralNames(ext_val_asn1.val)
#        else:
#            raise ext
            

class Extensions(list):
    """Extensions  ::=  SEQUENCE SIZE (1..MAX) OF Extension
    """
    def __init__(self, exts):
        assert isinstance(exts, asn1.Sequence)
        self.extend([Extension(ext) for ext in exts if isinstance(ext, asn1.Sequence)])
        
class SubjectPublicKeyInfo(ASN1Container):
    """SubjectPublicKeyInfo {ALGORITHM-IDENTIFIER:Algorithms} ::= SEQUENCE {
   algorithm         AlgorithmIdentifier {{Algorithms}},
   subjectPublicKey  BIT STRING}
    """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Sequence)
        self.PublicKeyAlgorithm = AlgorithmIdentifier(asn1_obj[0])
        self.PublicKey = asn1_obj[1].str
        
class TBSCertificate(ASN1Container):
    """TBSCertificate  ::=  SEQUENCE  {
        version         [0]  EXPLICIT Version DEFAULT v1,
        serialNumber         CertificateSerialNumber,
        signature            AlgorithmIdentifier,
        issuer               Name,
        validity             Validity,
        subject              Name,
        subjectPublicKeyInfo SubjectPublicKeyInfo,
        issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
                             -- If present, version MUST be v2 or v3
        subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
                             -- If present, version MUST be v2 or v3
        extensions      [3]  EXPLICIT Extensions OPTIONAL
                             -- If present, version MUST be v3
        }
        
        Name ::= CHOICE { RDNSequence }
        """
    def __init__(self, cert_asn1):
        assert isinstance(cert_asn1, asn1.Sequence)
        next = 0
        self.Version = 0
        if isinstance(cert_asn1[0], asn1.Contextual):
            self.Version = cert_asn1[0][0].val
            next = 1
        assert self.Version in (0, 1, 2)
        self.SerialNumber = cert_asn1[next].val
        next += 1
        self.Signature = AlgorithmIdentifier(cert_asn1[next])
        next += 1
        self.Issuer = str(RDNSequence(cert_asn1[next]))
        next += 1
        self.Validity = ASN1Container()
        try:
            self.Validity.check_type(cert_asn1[next][0], asn1.UTCTime)
            self.Validity.NotBefore=cert_asn1[next][0].datetime
            self.Validity.check_type(cert_asn1[next][1], asn1.UTCTime)
            self.Validity.NotAfter=cert_asn1[next][1].datetime
        except Exception, e:
            raise ValueError('Validity error: %s' % e)
        next += 1
        self.Subject = str(RDNSequence(cert_asn1[next]))
        next += 1
        self.SubjectPublicKeyInfo = SubjectPublicKeyInfo(cert_asn1[next])
        next += 1
        if self.Version > 1 and len(cert_asn1) == (next + 1): # only available in v3(2)
            if cert_asn1[next].tag == 3:
                self.Extensions = Extensions(cert_asn1[next][0])

class Certificate(ASN1Container):
    """Certificate  ::=  SEQUENCE  {
        tbsCertificate       TBSCertificate,
        signatureAlgorithm   AlgorithmIdentifier,
        signatureValue       BIT STRING  }
        """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Sequence)
        self.TBSCertificate = TBSCertificate(asn1_obj[0])
        self.SignatureAlgorithm = AlgorithmIdentifier(asn1_obj[1])
        self.SignatureValue = asn1_obj[2].str
        
class ExtendedCertificatesAndCertificates(list):
    """ExtendedCertificatesAndCertificates ::=  
        SET OF ExtendedCertificateOrCertificate
        
    ExtendedCertificateOrCertificate ::= CHOICE {  
        certificate Certificate, -- X.509  
        extendedCertificate [0] IMPLICIT ExtendedCertificate}
        """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Contextual)
        for cert in asn1_obj:
            self.append(Certificate(cert))
          
class DigestInfo(ASN1Container):
    """DigestInfo ::= SEQUENCE {
        digestAlgorithm     AlgorithmIdentifier,
        digest              OCTETSTRING}
    """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Sequence)
        self.DigestAlgorithm = AlgorithmIdentifier(asn1_obj[0])
        assert isinstance(asn1_obj[1], asn1.OctetString)
        self.Digest = asn1_obj[1].str
    
class SpcIndirectDataContent(ASN1Container):
    """SpcIndirectDataContent ::= SEQUENCE {
    data                    SpcAttributeTypeAndOptionalValue,
    messageDigest           DigestInfo}
    """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Sequence)
        self.Data = SpcAttributeTypeAndOptionalValue(asn1_obj[0])
        self.MessageDigest = DigestInfo(asn1_obj[1])

class ContentInfo(ASN1Container):
    """ContentInfo ::= SEQUENCE {
     contentType ContentType,
     content
       [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
    ContentType ::= OBJECT IDENTIFIER
    """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Sequence)
        self.ContentType = str(asn1_obj[0])
        assert self.ContentType == 'SPC_INDIRECT_DATA', \
            'must be set to SPC_INDIRECT_DATA_OBJ (1.3.6.1.4.1.311.2.1.4) not [%s (%s)]' % \
                (str(asn1_obj[0]), asn1_obj[0])
        if asn1_obj[1].tag == 0:
            self.Content = SpcIndirectDataContent(asn1_obj[1].val[0])

class DigestAlgorithmIdentifiers(list):
    """DigestAlgorithmIdentifiers ::=
      SET OF DigestAlgorithmIdentifier
    
    DigestAlgorithmIdentifier ::= AlgorithmIdentifier
    """
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Set)
        for i in asn1_obj:
            self.append(AlgorithmIdentifier(i))
        
class SignedData(ASN1Container):
    """Holds Certificate information.
    It's a SignedData(see: Windows Authenticode Portable Executable Signature Format)
    SignedData ::= SEQUENCE {
      version Version,
      digestAlgorithms DigestAlgorithmIdentifiers,
      contentInfo ContentInfo,
      certificates
            [0] IMPLICIT ExtendedCertificatesAndCertificates
           OPTIONAL,
      Crls
        [1] IMPLICIT CertificateRevocationLists OPTIONAL,
      signerInfos SignerInfos }
      
    SignerInfos ::= SET OF SignerInfo
    """
    
    def __init__(self, asn1_obj):
        assert isinstance(asn1_obj, asn1.Sequence)
        self.Version = asn1_obj[0].val
        assert self.Version == 1, 'version must be 1'
        digest_algorithms_asn1 = asn1_obj[1]
        assert len(digest_algorithms_asn1) == 1, 'Authenticode signatures support only one signer'
        self.DigestAlgorithms = DigestAlgorithmIdentifiers(digest_algorithms_asn1)
        self.ContentInfo = ContentInfo(asn1_obj[2])
        if asn1_obj[3].tag == 0:
            self.Certificates = ExtendedCertificatesAndCertificates(asn1_obj[3])
        signer_infos_asn1 = asn1_obj[4]
        self.SignerInfos = SignerInfos(signer_infos_asn1)
        for si in self.SignerInfos:
            assert si.DigestAlgorithm.Algorithm == self.DigestAlgorithms[0].Algorithm
    
    def _setattr(self, key, val, node):
        if isinstance(val, datetime):
            val = val.strftime('%Y-%m-%d %X')
        val = util.ensure_unicode(val)
        node.setAttribute(key, val)
        
    def create_xml_node(self, data, doc, parent, tagname=None):
        if tagname is None:
            tagname = data.__class__.__name__
        node = doc.createElement(tagname)
        parent.appendChild(node)
        if isinstance(data, list):
            for val in data:
                if isinstance(val, ASN1Container):
                    self.create_xml_node(val, doc, node)
                else:
                    raise val
        else:
            for key, val in data.__dict__.iteritems():
                if isinstance(val, ASN1Container) or isinstance(val, list):
                    self.create_xml_node(val, doc, node, key)
                else:
                    self._setattr(key, val, node)
        return node
        
    def toxml(self, xmlpath=None):
        doc = Document()
        signedData = self.create_xml_node(self, doc, doc)
        if xmlpath is not None:
            try:
                file = codecs.open(xmlpath, 'wb', 'utf-8')
                try:
                    doc.writexml(file, addindent=u'  ', newl=os.linesep, encoding='utf-8')
                finally:
                    file.close()
            except IOError, e:
                pass
        return doc